#ifdef _MINGW
	#include <unistd.h>
#endif


#include "gui/helpinfo.h"
#include "gui/statsgraph.h"
#include "gui/infobar.h"
#include "gui/infostats.h"
#include "gui/textverbosemessage.h"
#include "gui/mutationpanel.h"
#include "gui/globalsettingspanel.h"
#include "gui/settingsbrainpanel.h"
#include "gui/settingsbodypanel.h"
#include "gui/hud.h"
#include "gui/critterview.h"
#include "gui/brainview.h"
#include "gui/speciesview.h"

#include "gui/logbuffermessage.h"
#include "gui/exitpanel.h"
#include "gui/enginesettingspanel.h"


#include "entities/cdcommands.h"
#include "evolution.h"

# include <math.h>

Evolution::Evolution(int argc, char* argv[])
 : frameCounter(0)
{
	settings = Settings::Instance();
	eventsystem = BeEventSystem::Instance();
	eventsystem->setCommandsystem( Cdcommands::Instance() );
	Cdcommands::Instance()->scene = this;

	benchmark = settings->getCVarPtr("benchmark");
	headless = settings->getCVarPtr("headless");
	drawscene = settings->getCVarPtr("drawscene");

	unsigned int delay = 200;

 	Cdcommands::Instance()->registerCmd("quit", &Evolution::quit);
	Cdcommands::Instance()->registerCmd("cs_unregister", &Evolution::unregisterCritterVID);
	Cdcommands::Instance()->registerCmd("cs_clear", &Evolution::clear);

	Cdcommands::Instance()->registerCmd("decreaseenergy", &Evolution::decreaseenergy);
	Cdcommands::Instance()->registerCmd("increaseenergy", &Evolution::increaseenergy);
	Cdcommands::Instance()->registerCmd("dec_foodmaxenergy", &Evolution::decreasefoodmaxenergy);
	Cdcommands::Instance()->registerCmd("inc_foodmaxenergy", &Evolution::increasefoodmaxenergy);
	Cdcommands::Instance()->registerCmd("dec_worldsizex", &Evolution::dec_worldsizex);
	Cdcommands::Instance()->registerCmd("inc_worldsizex", &Evolution::inc_worldsizex);
	Cdcommands::Instance()->registerCmd("dec_worldsizey", &Evolution::dec_worldsizey);
	Cdcommands::Instance()->registerCmd("inc_worldsizey", &Evolution::inc_worldsizey);
	Cdcommands::Instance()->registerCmd("dec_worldsizez", &Evolution::dec_worldsizez);
	Cdcommands::Instance()->registerCmd("inc_worldsizez", &Evolution::inc_worldsizez);
	Cdcommands::Instance()->registerCmd("camera_moveup", &Evolution::camera_moveup);
	Cdcommands::Instance()->registerCmd("camera_movedown", &Evolution::camera_movedown);
	Cdcommands::Instance()->registerCmd("camera_moveforward", &Evolution::camera_moveforward);
	Cdcommands::Instance()->registerCmd("camera_movebackward", &Evolution::camera_movebackward);
	Cdcommands::Instance()->registerCmd("camera_moveleft", &Evolution::camera_moveleft);
	Cdcommands::Instance()->registerCmd("camera_moveright", &Evolution::camera_moveright);
	Cdcommands::Instance()->registerCmd("camera_lookup", &Evolution::camera_lookup);
	Cdcommands::Instance()->registerCmd("camera_lookdown", &Evolution::camera_lookdown);
	Cdcommands::Instance()->registerCmd("camera_lookleft", &Evolution::camera_lookleft);
	Cdcommands::Instance()->registerCmd("camera_lookright", &Evolution::camera_lookright);
	Cdcommands::Instance()->registerCmd("camera_rollleft", &Evolution::camera_rollleft);
	Cdcommands::Instance()->registerCmd("camera_rollright", &Evolution::camera_rollright);
// 	Cdcommands::Instance()->registerCmd("camera_lookhorizontal", &Evolution::camera_lookhorizontal);
// 	Cdcommands::Instance()->registerCmd("camera_lookvertical", &Evolution::camera_lookvertical);
// 	Cdcommands::Instance()->registerCmd("camera_movehorizontal", &Evolution::camera_movehorizontal);
// 	Cdcommands::Instance()->registerCmd("camera_movevertical", &Evolution::camera_movevertical);
	Cdcommands::Instance()->registerCmd("cs_selectall", &Evolution::selectCritterAll);

	Cdcommands::Instance()->registerCmd("loadallcritters", &WorldB::loadAllCritters);
	Cdcommands::Instance()->registerCmd("saveallcritters", &WorldB::saveAllCritters);
	Cdcommands::Instance()->registerCmd("insertcritter", &WorldB::insertCritter);
	Cdcommands::Instance()->registerCmd("killhalfofcritters", &WorldB::killHalfOfCritters);
	Cdcommands::Instance()->registerCmd("camera_resetposition", &WorldB::resetCamera);
	Cdcommands::Instance()->registerCmd("toggle_pause", &WorldB::togglePause);
// 	Cdcommands::Instance()->registerCmd("toggle_sleeper", &WorldB::toggleSleeper);
	Cdcommands::Instance()->registerCmd("toggle_mouselook", &WorldB::toggleMouselook);
	Cdcommands::Instance()->registerCmd("critter_select", &WorldB::selectBody);
	Cdcommands::Instance()->registerCmd("critter_deselect", &WorldB::deselectBody);
	Cdcommands::Instance()->registerCmd("critter_pick", &WorldB::pickBody);
	Cdcommands::Instance()->registerCmd("critter_unpick", &WorldB::unpickBody);
	Cdcommands::Instance()->registerCmd("cs_kill", &WorldB::removeSelectedCritter);
	Cdcommands::Instance()->registerCmd("cs_killall", &WorldB::removeAllSelectedCritters);
	Cdcommands::Instance()->registerCmd("cs_duplicate", &WorldB::duplicateSelectedCritter);
	Cdcommands::Instance()->registerCmd("cs_spawnbrainmutant", &WorldB::spawnBrainMutantSelectedCritter);
	Cdcommands::Instance()->registerCmd("cs_spawnbodymutant", &WorldB::spawnBodyMutantSelectedCritter);
	Cdcommands::Instance()->registerCmd("cs_spawnbrainbodymutant", &WorldB::spawnBrainBodyMutantSelectedCritter);
	Cdcommands::Instance()->registerCmd("cs_duplicateall", &WorldB::duplicateAllSelectedCritters);
	Cdcommands::Instance()->registerCmd("cs_spawnbrainmutantall", &WorldB::spawnBrainMutantAllSelectedCritters);
	Cdcommands::Instance()->registerCmd("cs_spawnbodymutantall", &WorldB::spawnBodyMutantAllSelectedCritters);
	Cdcommands::Instance()->registerCmd("cs_spawnbrainbodymutantall", &WorldB::spawnBrainBodyMutantAllSelectedCritters);
	Cdcommands::Instance()->registerCmd("cs_feed", &WorldB::feedSelectedCritter);
	Cdcommands::Instance()->registerCmd("cs_resetage", &WorldB::resetageSelectedCritter);

	Cdcommands::Instance()->registerCmd("cs_select", &Evolution::gui_selectCritter);
	Cdcommands::Instance()->registerCmd("gui_togglepanel", &Evolution::canvas_swapchild);
	Cdcommands::Instance()->registerCmd("gui_toggle", &Evolution::gui_swap);

	Cdcommands::Instance()->registerCmd("canvas_setx", &Evolution::canvas_setx);
	Cdcommands::Instance()->registerCmd("canvas_sety", &Evolution::canvas_sety);
	Cdcommands::Instance()->registerCmd("canvas_press", &Evolution::canvas_press);
	Cdcommands::Instance()->registerCmd("canvas_release", &Evolution::canvas_release);
	Cdcommands::Instance()->registerCmd("canvas_pressAlt", &Evolution::canvas_pressAlt);
	Cdcommands::Instance()->registerCmd("canvas_releaseAlt", &Evolution::canvas_releaseAlt);
	// 	Commands::Instance()->registerCmd("loadallcritters", &WorldB::loadAllCritters);
	
	// modifiers

	// + 2048 -> buttons pressed
	// + 2148 -> buttons released
	// + 1224 -> mouse axis

	Execcmd execcmd;
// 	BeEventSystem::Instance()->registerEvent( DOWN, SDLK_LSHIFT, 2048+1,	"critter_deselect", execcmd.gen("critter_deselect"), 0, 0, 0 );
// 	BeEventSystem::Instance()->registerEvent( DOWN, SDLK_RSHIFT, 2048+1,	"critter_deselect", execcmd.gen("critter_deselect"), 0, 0, 0 );

	// HACK passes through canvas, so was moved to canvas_press
// 	BeEventSystem::Instance()->registerEvent( DOWN, 2048+1,			boost::shared_ptr<Event>(new Event( execcmd.gen("critter_select"), EVENT_NOREPEAT) ) );
	BeEventSystem::Instance()->registerEvent( DOWN, 2048+2,			boost::shared_ptr<Event>(new Event( execcmd.gen("camera_resetposition"), EVENT_NOREPEAT) ) );

	// HACK passes through canvas, so was moved to canvas_press
// 	BeEventSystem::Instance()->registerEvent( DOWN, 2048+3,			boost::shared_ptr<Event>(new Event( execcmd.gen("critter_pick"), EVENT_NOREPEAT) ) );
// 	BeEventSystem::Instance()->registerEvent( UP, 2048+3,			boost::shared_ptr<Event>(new Event( execcmd.gen("critter_unpick"), EVENT_NOREPEAT) ) );
	
	BeEventSystem::Instance()->registerEvent( DOWN, 2048+4,			boost::shared_ptr<Event>(new Event( execcmd.gen("camera_moveforward"), EVENT_NOREPEAT) ) );
	BeEventSystem::Instance()->registerEvent( DOWN, 2048+5,			boost::shared_ptr<Event>(new Event( execcmd.gen("camera_movebackward"), EVENT_NOREPEAT) ) );
	
// 	BeEventSystem::Instance()->registerEvent( DOWN, 2248+0,			"camera_lookhorizontal", execcmd.gen("camera_lookhorizontal"), 0, 0, 0 );
// 	BeEventSystem::Instance()->registerEvent( DOWN, 2248+1,			"camera_lookvertical", execcmd.gen("camera_lookvertical"), 0, 0, 0 );

	// events
	BeEventSystem::Instance()->registerEvent( DOWN, SDLK_TAB,		boost::shared_ptr<Event>(new Event( execcmd.gen("gui_togglepanel", "speciesview"), EVENT_NOREPEAT) ) );
	BeEventSystem::Instance()->registerEvent( DOWN, SDLK_ESCAPE,		boost::shared_ptr<Event>(new Event( execcmd.gen("gui_togglepanel", "panel_exit"), EVENT_NOREPEAT) ) );
	BeEventSystem::Instance()->registerEvent( DOWN, SDLK_F1,		boost::shared_ptr<Event>(new Event( execcmd.gen("gui_togglepanel", "helpinfo"), EVENT_NOREPEAT) ) );

	BeEventSystem::Instance()->registerEvent( DOWN, SDLK_F2,		boost::shared_ptr<Event>(new Event( execcmd.gen("gui_togglepanel", "infobar"), EVENT_NOREPEAT) ) );
	BeEventSystem::Instance()->registerEvent( DOWN, SDLK_F3,		boost::shared_ptr<Event>(new Event( execcmd.gen("gui_togglepanel", "infostats"), EVENT_NOREPEAT) ) );
	BeEventSystem::Instance()->registerEvent( DOWN, SDLK_F4,		boost::shared_ptr<Event>(new Event( execcmd.gen("gui_togglepanel", "textverbosemessage"), EVENT_NOREPEAT) ) );

	BeEventSystem::Instance()->registerEvent( DOWN, SDLK_F5,		boost::shared_ptr<Event>(new Event( execcmd.gen("gui_togglepanel", "statsgraph"), EVENT_NOREPEAT) ) );
	BeEventSystem::Instance()->registerEvent( DOWN, SDLK_F6,		boost::shared_ptr<Event>(new Event( execcmd.gen("gui_togglepanel", "globalsettingspanel"), EVENT_NOREPEAT) ) );
	BeEventSystem::Instance()->registerEvent( DOWN, SDLK_F7,		boost::shared_ptr<Event>(new Event( execcmd.gen("gui_togglepanel", "enginesettingspanel"), EVENT_NOREPEAT) ) );
	BeEventSystem::Instance()->registerEvent( DOWN, SDLK_F8,		boost::shared_ptr<Event>(new Event( execcmd.gen("gui_togglepanel", "hud"), EVENT_NOREPEAT) ) );

	BeEventSystem::Instance()->registerEvent( DOWN, SDLK_f,			boost::shared_ptr<Event>(new Event( execcmd.gen("settings_increase", "fullscreen"), EVENT_NOREPEAT) ) );
	BeEventSystem::Instance()->registerEvent( DOWN, SDLK_r,			boost::shared_ptr<Event>(new Event( execcmd.gen("settings_increase", "drawscene"), EVENT_NOREPEAT) ) );
	BeEventSystem::Instance()->registerEvent( DOWN, SDLK_p,			boost::shared_ptr<Event>(new Event( execcmd.gen("toggle_pause"), EVENT_NOREPEAT) ) );

	BeEventSystem::Instance()->registerEvent( DOWN, SDLK_l,			boost::shared_ptr<Event>(new Event( execcmd.gen("settings_increase", "fpslimit"), EVENT_NOREPEAT) ) );
	BeEventSystem::Instance()->registerEvent( DOWN, SDLK_m,			boost::shared_ptr<Event>(new Event( execcmd.gen("toggle_mouselook"), EVENT_NOREPEAT) ) );
	BeEventSystem::Instance()->registerEvent( DOWN, SDLK_s,			boost::shared_ptr<Event>(new Event( execcmd.gen("settings_saveprofile"), EVENT_NOREPEAT) ) );
	BeEventSystem::Instance()->registerEvent( DOWN, SDLK_h,			boost::shared_ptr<Event>(new Event( execcmd.gen("gui_toggle"), EVENT_NOREPEAT) ) );

	BeEventSystem::Instance()->registerEvent( DOWN, SDLK_KP_DIVIDE,		boost::shared_ptr<Event>(new Event( execcmd.gen("settings_decrease", "camerasensitivity"), EVENT_NOREPEAT) ) );

	BeEventSystem::Instance()->registerEvent( DOWN, SDLK_KP_MULTIPLY,	boost::shared_ptr<Event>(new Event( execcmd.gen("settings_increase", "camerasensitivity"), EVENT_REPEAT, delay) ) );
	BeEventSystem::Instance()->registerEvent( DOWN, SDLK_c,			boost::shared_ptr<Event>(new Event( execcmd.gen("settings_increase", "colormode"), EVENT_NOREPEAT) ) );

	BeEventSystem::Instance()->registerEvent( DOWN, SDLK_F9,		boost::shared_ptr<Event>(new Event( execcmd.gen("settings_decrease", "body_mutationrate"), EVENT_REPEAT, delay) ) );
	BeEventSystem::Instance()->registerEvent( DOWN, SDLK_F10,		boost::shared_ptr<Event>(new Event( execcmd.gen("settings_increase", "body_mutationrate"), EVENT_REPEAT, delay) ) );
// 	BeEventSystem::Instance()->registerEvent( DOWN, SDLK_LSHIFT, SDLK_F9,	boost::shared_ptr<Event>(new Event( execcmd.gen("settings_decrease", "body_maxmutations"), EVENT_REPEAT, delay) ) );
// 	BeEventSystem::Instance()->registerEvent( DOWN, SDLK_LSHIFT, SDLK_F10,	boost::shared_ptr<Event>(new Event( execcmd.gen("settings_increase", "body_maxmutations"), EVENT_REPEAT, delay) ) );
// 	BeEventSystem::Instance()->registerEvent( DOWN, SDLK_RSHIFT, SDLK_F9,	boost::shared_ptr<Event>(new Event( execcmd.gen("settings_decrease", "body_maxmutations"), EVENT_REPEAT, delay) ) );
// 	BeEventSystem::Instance()->registerEvent( DOWN, SDLK_RSHIFT, SDLK_F10,	boost::shared_ptr<Event>(new Event( execcmd.gen("settings_increase", "body_maxmutations"), EVENT_REPEAT, delay) ) );
	
	BeEventSystem::Instance()->registerEvent( DOWN, SDLK_F11,		boost::shared_ptr<Event>(new Event( execcmd.gen("settings_decrease", "brain_mutationrate"), EVENT_REPEAT, delay) ) );
	BeEventSystem::Instance()->registerEvent( DOWN, SDLK_F12,		boost::shared_ptr<Event>(new Event( execcmd.gen("settings_increase", "brain_mutationrate"), EVENT_REPEAT, delay) ) );
// 	BeEventSystem::Instance()->registerEvent( DOWN, SDLK_LSHIFT, SDLK_F11,	boost::shared_ptr<Event>(new Event( execcmd.gen("settings_decrease", "brain_maxmutations"), EVENT_REPEAT, delay) ) );
// 	BeEventSystem::Instance()->registerEvent( DOWN, SDLK_LSHIFT, SDLK_F12,	boost::shared_ptr<Event>(new Event( execcmd.gen("settings_increase", "brain_maxmutations"), EVENT_REPEAT, delay) ) );
// 	BeEventSystem::Instance()->registerEvent( DOWN, SDLK_RSHIFT, SDLK_F11,	boost::shared_ptr<Event>(new Event( execcmd.gen("settings_decrease", "brain_maxmutations"), EVENT_REPEAT, delay) ) );
// 	BeEventSystem::Instance()->registerEvent( DOWN, SDLK_RSHIFT, SDLK_F12,	boost::shared_ptr<Event>(new Event( execcmd.gen("settings_increase", "brain_maxmutations"), EVENT_REPEAT, delay) ) );
	
	BeEventSystem::Instance()->registerEvent( DOWN, SDLK_PAGEUP,		boost::shared_ptr<Event>(new Event( execcmd.gen("loadallcritters"), EVENT_NOREPEAT) ) );
	BeEventSystem::Instance()->registerEvent( DOWN, SDLK_PAGEDOWN,		boost::shared_ptr<Event>(new Event( execcmd.gen("saveallcritters"), EVENT_NOREPEAT) ) );
	BeEventSystem::Instance()->registerEvent( DOWN, SDLK_i,			boost::shared_ptr<Event>(new Event( execcmd.gen("insertcritter"), EVENT_NOREPEAT) ) );
	BeEventSystem::Instance()->registerEvent( DOWN, SDLK_k,			boost::shared_ptr<Event>(new Event( execcmd.gen("killhalfofcritters"), EVENT_NOREPEAT) ) );

	BeEventSystem::Instance()->registerEvent( DOWN, SDLK_MINUS,		boost::shared_ptr<Event>(new Event( execcmd.gen("decreaseenergy"), EVENT_REPEAT, delay) ) );
	BeEventSystem::Instance()->registerEvent( DOWN, SDLK_PLUS,		boost::shared_ptr<Event>(new Event( execcmd.gen("increaseenergy"), EVENT_REPEAT, delay) ) );
	BeEventSystem::Instance()->registerEvent( DOWN, SDLK_KP_MINUS,		boost::shared_ptr<Event>(new Event( execcmd.gen("decreaseenergy"), EVENT_REPEAT, delay) ) );
	BeEventSystem::Instance()->registerEvent( DOWN, SDLK_KP_PLUS,		boost::shared_ptr<Event>(new Event( execcmd.gen("increaseenergy"), EVENT_REPEAT, delay) ) );

        BeEventSystem::Instance()->registerEvent( DOWN, SDLK_BACKSPACE,		boost::shared_ptr<Event>(new Event( execcmd.gen("camera_resetposition"), EVENT_NOREPEAT) ) );
	
	BeEventSystem::Instance()->registerEvent( DOWN, SDLK_HOME,		boost::shared_ptr<Event>(new Event( execcmd.gen("camera_moveup"), EVENT_REPEAT) ) );
	BeEventSystem::Instance()->registerEvent( DOWN, SDLK_END,		boost::shared_ptr<Event>(new Event( execcmd.gen("camera_movedown"), EVENT_REPEAT) ) );
	BeEventSystem::Instance()->registerEvent( DOWN, SDLK_UP,		boost::shared_ptr<Event>(new Event( execcmd.gen("camera_moveforward"), EVENT_REPEAT) ) );
	BeEventSystem::Instance()->registerEvent( DOWN, SDLK_DOWN,		boost::shared_ptr<Event>(new Event( execcmd.gen("camera_movebackward"), EVENT_REPEAT) ) );
	BeEventSystem::Instance()->registerEvent( DOWN, SDLK_LEFT,		boost::shared_ptr<Event>(new Event( execcmd.gen("camera_moveleft"), EVENT_REPEAT) ) );
	BeEventSystem::Instance()->registerEvent( DOWN, SDLK_RIGHT,		boost::shared_ptr<Event>(new Event( execcmd.gen("camera_moveright"), EVENT_REPEAT) ) );
	BeEventSystem::Instance()->registerEvent( DOWN, SDLK_KP2,		boost::shared_ptr<Event>(new Event( execcmd.gen("camera_lookup"), EVENT_REPEAT) ) );
	BeEventSystem::Instance()->registerEvent( DOWN, SDLK_KP8,		boost::shared_ptr<Event>(new Event( execcmd.gen("camera_lookdown"), EVENT_REPEAT) ) );
	BeEventSystem::Instance()->registerEvent( DOWN, SDLK_KP4,		boost::shared_ptr<Event>(new Event( execcmd.gen("camera_lookleft"), EVENT_REPEAT) ) );
	BeEventSystem::Instance()->registerEvent( DOWN, SDLK_KP6,		boost::shared_ptr<Event>(new Event( execcmd.gen("camera_lookright"), EVENT_REPEAT) ) );
	BeEventSystem::Instance()->registerEvent( DOWN, SDLK_KP1,		boost::shared_ptr<Event>(new Event( execcmd.gen("camera_rollleft"), EVENT_REPEAT) ) );
	BeEventSystem::Instance()->registerEvent( DOWN, SDLK_KP3,		boost::shared_ptr<Event>(new Event( execcmd.gen("camera_rollright"), EVENT_REPEAT) ) );

	// mouse/canvas axis events
	Textverbosemessage* textverbosemessage = 0;

	if ( settings->getCVar("headless") == 0 )
	{
		glwindow = new GLWindow();
		glwindow->create("Critterding beta13", 800, 600);

		canvas = new Canvas();

		cmdsettings cmdx = execcmd.gen( "canvas_setx", 0.0f );
		boost::shared_ptr<Event> eventx(new Event(cmdx, EVENT_NOREPEAT));
		boost::shared_ptr<VirtualAxis> virtualaxisx(new VirtualAxis(eventx, 0, 10000, 0, 0));
		BeEventSystem::Instance()->registerEvent( 0+7168, virtualaxisx );

		cmdsettings cmdy = execcmd.gen( "canvas_sety", 0.0f );
		boost::shared_ptr<Event> eventy(new Event(cmdy, EVENT_NOREPEAT));
		boost::shared_ptr<VirtualAxis> virtualaxisy(new VirtualAxis(eventy, 0, 10000, 0, 0));
		BeEventSystem::Instance()->registerEvent( 1+7168, virtualaxisy );

		// button press / release
			cmdsettings cmdDown = execcmd.gen("canvas_press");
			eventsystem->registerEvent( DOWN, 1+2048, boost::shared_ptr<Event>(new Event(cmdDown, EVENT_NOREPEAT, 0)) );
			cmdsettings cmdUp = execcmd.gen("canvas_release");
			eventsystem->registerEvent( UP,   1+2048, boost::shared_ptr<Event>(new Event(cmdUp, EVENT_NOREPEAT, 0)) );
		
			cmdsettings cmdDownAlt = execcmd.gen("canvas_pressAlt");
			eventsystem->registerEvent( DOWN, 3+2048, boost::shared_ptr<Event>(new Event(cmdDownAlt, EVENT_NOREPEAT, 0)) );
			cmdsettings cmdUpAlt = execcmd.gen("canvas_releaseAlt");
			eventsystem->registerEvent( UP,   3+2048, boost::shared_ptr<Event>(new Event(cmdUpAlt, EVENT_NOREPEAT, 0)) );
		
		textverbosemessage = static_cast<Textverbosemessage*>( canvas->addWidgetPanel( "textverbosemessage", new Textverbosemessage() ) );
	}

	if ( settings->getCVar("race") == 1 )
		world = new WorldRace( textverbosemessage );
	else if ( settings->getCVar("roundworld") == 1 )
		world = new Roundworld( textverbosemessage );
	else if ( settings->getCVar("concavefloor") == 1 )
		world = new Concavefloor( textverbosemessage );
	else
		world = new WorldB( textverbosemessage );

	Cdcommands::Instance()->world = world;
	if ( !*world->headless )
	{
		// init gui panels
		canvas->addWidgetPanel( "enginesettingspanel", new Enginesettingspanel() );
		canvas->addWidgetPanel( "helpinfo", new Helpinfo() );
		canvas->addWidgetPanel( "logbuffermessage", new Logbuffermessage() );
		canvas->addWidgetPanel( "statsgraph", new Statsgraph() );
		canvas->addWidgetPanel( "infobar", new Infobar() );
		canvas->addWidgetPanel( "infostats", new Infostats() );
		canvas->addWidgetPanel( "panel_exit", new Exitpanel() );
		canvas->addWidgetPanel( "mutationpanel", new Mutationpanel() );
		canvas->addWidgetPanel( "globalsettingspanel", new Globalsettingspanel() );
		canvas->addWidgetPanel( "settingsbrainpanel", new Settingsbrainpanel() );
		canvas->addWidgetPanel( "settingsbodypanel", new Settingsbodypanel() );
		canvas->addWidgetPanel( "critterview", new Critterview() );
		canvas->addWidgetPanel( "brainview", new Brainview() );
		canvas->addWidgetPanel( "hud", new Hud() );
		canvas->addWidgetPanel( "speciesview", new Speciesview() );
		canvas->setDefaultZAxis();

		static_cast<Hud*>(canvas->children["hud"])->world = world;
		static_cast<Critterview*>(canvas->children["critterview"])->world = world;
	}
	else
	{
		// check if raycastvision is enabled, if not die
		if ( settings->getCVar("critter_raycastvision") == 0 )
		{
			cerr << "headless mode requires critter_raycastvision to be enabled" << endl;
			exit(1);
		}
	}

	if ( *benchmark == 1 )
	{
		canvas->active = false;
		settings->setCVar("startseed", 11);
	}


	world->init();
}

void Evolution::draw()
{
	Timer::Instance()->mark();
	world->framelimiter.mark( Timer::Instance() );
	frameCounter++;

	const float timeDelta=Timer::Instance()->elapsed / 1000.0f;
	m_cameraTranslateSpeed=40.0f*timeDelta; //0.5f**m_cameraSensitivity;
	m_cameraRotateSpeed=SIMD_2_PI*timeDelta; //0.0001f**m_cameraSensitivity;

	if ( *benchmark == 1 )
	{
		if ( frameCounter == 1000 )
		{
			float ms = Timer::Instance()->sdl_lasttime - Timer::Instance()->sdl_firsttime;
			cerr << "benchmark: ran " << frameCounter << " frames in " << ms/1000 << " sec, avg: " << (float)frameCounter / ms * 1000 << endl;
			cerr << "and btw, freeEnergy: " << world->freeEnergy << ", critters: " << world->critters.size() << endl;
			exit(0);
		}
	}
	
	if ( !*world->headless )
	{
		glwindow->process();
		
		eventsystem->processEvents( Timer::Instance()->elapsed );
	
		glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

	// 3D
// 		GLfloat ambientLight[] = {0.5f, 0.5f, 0.5f, 1.0f};
		GLfloat ambientLight[] = {0.6f, 0.6f, 0.6f, 0.0f};
		glLightModelfv(GL_LIGHT_MODEL_AMBIENT, ambientLight);
// 		GLfloat lightColor[] = { 0.1f, 0.1f, 0.1f, 1.0f };

		GLfloat lightColor[] = { 0.04f, 0.04f, 0.04f, 0.0f };

		GLfloat lightPos[] = { 0.5f * *world->worldsizeX, 50.0f, 0.5f * *world->worldsizeY, 1.0f };
// 		GLfloat lightPos1[] = { 0.0f, 20.0f, 0.5f*settings->getCVar("worldsizeY"), 1.0f };
// 		GLfloat lightPos2[] = { settings->getCVar("worldsizeX")+1.0f, 20, 0.5f*settings->getCVar("worldsizeY"), 1.0f };
		glLightfv(GL_LIGHT0, GL_DIFFUSE, lightColor);
		glLightfv(GL_LIGHT0, GL_POSITION, lightPos);
// 		glLightfv(GL_LIGHT0, GL_DIFFUSE, lightColor);
// 		glLightfv(GL_LIGHT0, GL_POSITION, lightPos1);
// 		glLightfv(GL_LIGHT1, GL_DIFFUSE, lightColor);
// 		glLightfv(GL_LIGHT1, GL_POSITION, lightPos2);

		glEnable(GL_DEPTH_TEST);
		glEnable(GL_COLOR_MATERIAL);
		glEnable(GL_LIGHTING);
		glEnable(GL_LIGHT0);
		
// 		glEnable(GL_LIGHT1);
// 		glEnable(GL_CULL_FACE);
// 		glCullFace(GL_BACK);

		glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST);
// 		glHint(GL_FOG_HINT, GL_FASTEST);
// 		glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);

		glShadeModel(GL_FLAT);
// 		glShadeModel(GL_SMOOTH);

		glDisable(GL_DITHER);
		glDisable(GL_POLYGON_SMOOTH);
	}

	world->process(frameCounter);

	if ( !*world->headless )
	{

// 			if (world->critters.size() > 1 )
// 			{
// 				world->camera.follow( (btDefaultMotionState*)world->critters[0]->body.mouths[0]->body->getMotionState() );
// 				world->drawWithoutFaces();
// 				world->critters[0]->printVision();
// 			}

// 		world->camera.place(1);
// 		world->m_sceneNodeCamera.setOrigin( btVector3( 0, 0, 0 ) );
		glViewport(0,0,*settings->winWidth,*settings->winHeight);
		world->m_graphicsSystem.applyCamera(world->m_camera);


		if ( *drawscene == 1 )
		{
// 		glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST);
// 		glHint(GL_FOG_HINT, GL_FASTEST);
		glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);

// 		glShadeModel(GL_FLAT);
		glShadeModel(GL_SMOOTH);


			world->drawWithGrid();

			// draw selected info
			btScalar position[16];
			btTransform trans;
			trans.setIdentity();

			btTransform up;
			up.setIdentity();
			up.setOrigin( btVector3(0.0f, 0.2f, 0.0f) );

			for ( unsigned int i=0; i < world->critterselection->clist.size(); i++ )
			{
        Mouth *m = dynamic_cast<Mouth*>(world->critterselection->clist[i]->body.bodyparts[0]);
        if(m == NULL)
        {
          cerr << "Render error, first bodypart is not Mouth." << endl;
        }
        else
        {
          trans.setOrigin(m->ghostObject->getWorldTransform().getOrigin());
          trans.getOrigin().setY(trans.getOrigin().getY()+0.5f);
          trans.setBasis(world->m_sceneNodeCamera.getTransform().getBasis());
          trans *= up;
          trans.getOpenGLMatrix(position);

          glPushMatrix(); 
  // 				glMultMatrixf(position);
  // 				glMultMatrixd(position); // FIXME WATCHIT OK WENT TO DOUBLE HERE 
          Displaylists::Instance()->glMultiMatrix(position);

            glColor3f(1.5f, 1.5f, 1.5f);
            glBegin(GL_LINES);
              glVertex2f(-0.2f, 0.05f);
              glVertex2f(-0.2f,-0.05f);

              glVertex2f(-0.2f,-0.05f);
              glVertex2f(0.2f, -0.05f);

              glVertex2f(0.2f, -0.05f);
              glVertex2f(0.2f,  0.05f);

              glVertex2f(0.2f,  0.05f);
              glVertex2f(-0.2f, 0.05f);
            glEnd();

          glPopMatrix();
        }
			}
		}

	// 2D
		if ( canvas->active )
		{
			glDisable(GL_DEPTH_TEST);
			glDisable (GL_LIGHTING);
			glDisable(GL_LIGHT0);
	// 		glDisable(GL_LIGHT1);
			glDisable(GL_COLOR_MATERIAL);
	// 		glDisable(GL_DITHER);
	// 		glDisable(GL_CULL_FACE);

			world->m_graphicsSystem.matrixLoadIdentity(GL_PROJECTION);
			world->m_graphicsSystem.matrixOrtho(GL_PROJECTION, 0, *settings->winWidth, *settings->winHeight, 0,  0, 1);
			world->m_graphicsSystem.matrixLoadIdentity(GL_MODELVIEW);
			world->m_graphicsSystem.matrixTranslate(GL_MODELVIEW, 0.5f, -0.5f, 0.0f); // pixel precision offset			

// 			glPushMatrix();

			canvas->draw();

			if ( *drawscene == 1 )
			{
				if (!world->mouselook && !canvas->mouseFocus )
				{
					world->castMouseRay();

					// hover test
					if ( world->mouseRayHit )
					{
						unsigned int margin = 20;
						unsigned int rmargindistance = 70;
						unsigned int vspacer = 12;
						glColor3f(1.0f, 1.0f, 1.0f);
						if ( world->mouseRayHitEntity->type == FOOD )
						{
							Textprinter::Instance()->print( world->mousex+margin, world->mousey,    "food");
							Textprinter::Instance()->print( world->mousex+margin, world->mousey+vspacer, "energy");
							Textprinter::Instance()->print(world->mousex+rmargindistance, world->mousey+vspacer, "%1.1f", static_cast<Bodypart*>(world->mouseRayHitEntity)->getOwner_food()->energyLevel);
						}
						else if ( world->mouseRayHitEntity->type == CRITTER )
						{
							const CritterB* c = static_cast<Bodypart*>(world->mouseRayHitEntity)->getOwner_critter();
							Textprinter::Instance()->print( world->mousex+margin, world->mousey,    "critter");
							Textprinter::Instance()->print(world->mousex+rmargindistance, world->mousey, "%1i", c->critterID);
							Textprinter::Instance()->print( world->mousex+margin, world->mousey+vspacer, "energy");
							Textprinter::Instance()->print(world->mousex+rmargindistance, world->mousey+vspacer, "%1.1f", c->energyLevel);
						}
					}
				}
			}
// 			glPopMatrix();
		}
		SDL_GL_SwapBuffers();		
	}

	if ( world->critters.size() == 0 && settings->getCVar("exit_if_empty") )
	{
		cerr << "world is empty, exiting..." << endl;
// 		Cdcommands::Instance()->quit();
		quit();
	}
}

// void Evolution::handleMouseMotionAbs(int x, int y)
// {
// 	if ( !world->mouselook )
// 	{
// 		world->mousex = x;
// 		world->mousey = y;
// 		
// 		// world mouse dynamics
// 		world->calcMouseDirection();
// 		world->movePickedBodyTo();
// 	}
// }

// void Evolution::handleMouseMotionRel(int x, int y)
// {
// 	if ( world->mouselook )
// 	{
// 		world->relx = x;
// 		world->rely = y;
// 		eventsystem->activateKeystate(2248+0);
// 		eventsystem->activateKeystate(2248+1);
// 	}
// }

// COMMANDS
	void Evolution::selectCritterAll()
	{
		world->critterselection->clear();
		for ( unsigned int i=0; i < world->critters.size(); i++ )
			world->critterselection->registerCritter(world->critters[i]);
	}

	// FIXME Move this shit to evolution.cpp?
	void Evolution::selectCritter(const unsigned int& c)
	{
	// 	canvas->swapChild("critterview");
		world->critterselection->selectCritterVID(c);
	}

	void Evolution::decreaseenergy()
	{
		if ( ( (int)settings->getCVar("energy") - 1 ) >= 0 )
		{
			settings->setCVar("energy", settings->getCVar("energy")-1 );
			world->freeEnergy -= settings->getCVar("food_maxenergy");
			
			stringstream buf;
			buf << "energy: " << settings->getCVar("energy");
			Logbuffer::Instance()->add(buf);
		}
	}

	void Evolution::increaseenergy()
	{
		settings->setCVar("energy", settings->getCVar("energy")+1 );
		world->freeEnergy += settings->getCVar("food_maxenergy");

		stringstream buf;
		buf << "energy: " << settings->getCVar("energy");
		Logbuffer::Instance()->add(buf);
	}

	void Evolution::decreasefoodmaxenergy()
	{
		if ( ( (int)settings->getCVar("food_maxenergy") - 1 ) >= 0 )
		{
			world->freeEnergy -= settings->getCVar("energy");
			settings->setCVar("food_maxenergy", settings->getCVar("food_maxenergy")-1 );
		}
	}

	void Evolution::increasefoodmaxenergy()
	{
		world->freeEnergy += settings->getCVar("energy");
		settings->setCVar("food_maxenergy", settings->getCVar("food_maxenergy")+1 );
	}

	void Evolution::dec_worldsizex() { settings->decreaseCVar("worldsizeX"); world->makeFloor(); }
	void Evolution::inc_worldsizex() { settings->increaseCVar("worldsizeX"); world->makeFloor(); }
	void Evolution::dec_worldsizey() { settings->decreaseCVar("worldsizeY"); world->makeFloor(); }
	void Evolution::inc_worldsizey() { settings->increaseCVar("worldsizeY"); world->makeFloor(); }
	void Evolution::dec_worldsizez() { settings->decreaseCVar("worldsizeZ"); world->makeFloor(); }
	void Evolution::inc_worldsizez() { settings->increaseCVar("worldsizeZ"); world->makeFloor(); }

	void Evolution::camera_moveup()
	{
		BeSceneNode* const sceneNode=world->m_camera.getSceneNode();
		if(sceneNode)
		{
			sceneNode->translateLocal(btVector3(0,m_cameraTranslateSpeed,0));
		}
		world->movePickedBodyFrom();
	}
	void Evolution::camera_movedown()
	{
		BeSceneNode* const sceneNode=world->m_camera.getSceneNode();
		if(sceneNode)
		{
			sceneNode->translateLocal(btVector3(0,-m_cameraTranslateSpeed,0));
		}
		world->movePickedBodyFrom();
	}
	void Evolution::camera_moveforward() 	
	{ 
		BeSceneNode* const sceneNode=world->m_camera.getSceneNode();
		if(sceneNode)
		{
			sceneNode->translateLocal(btVector3(0,0,-m_cameraTranslateSpeed));
		}
		world->movePickedBodyFrom(); 
	}
	void Evolution::camera_movebackward() 	
	{ 
		BeSceneNode* const sceneNode=world->m_camera.getSceneNode();
		if(sceneNode)
		{
			sceneNode->translateLocal(btVector3(0,0,m_cameraTranslateSpeed));
		}
		world->movePickedBodyFrom(); 
	}
	void Evolution::camera_moveleft() 		
	{ 
		BeSceneNode* const sceneNode=world->m_camera.getSceneNode();
		if(sceneNode)
		{
			sceneNode->translateLocal(btVector3(-m_cameraTranslateSpeed,0,0));
		}
		world->movePickedBodyFrom(); 
	}
	void Evolution::camera_moveright() 		
	{ 
		BeSceneNode* const sceneNode=world->m_camera.getSceneNode();
		if(sceneNode)
		{
			sceneNode->translateLocal(btVector3(m_cameraTranslateSpeed,0,0));
		}
		world->movePickedBodyFrom(); 
	}
	void Evolution::camera_lookup() 		
	{ 
		BeSceneNode* const sceneNode=world->m_camera.getSceneNode();
		if(sceneNode)
		{
			sceneNode->pitch(m_cameraRotateSpeed);
		}
		world->calcMouseDirection(); 
		world->movePickedBodyTo(); 
	}
	void Evolution::camera_lookdown() 		
	{ 
		BeSceneNode* const sceneNode=world->m_camera.getSceneNode();
		if(sceneNode)
		{
			sceneNode->pitch(-m_cameraRotateSpeed);
		}
		world->calcMouseDirection(); 
		world->movePickedBodyTo(); 
	}
	void Evolution::camera_lookleft() 		
	{ 
		BeSceneNode* const sceneNode=world->m_camera.getSceneNode();
		if(sceneNode)
		{
			sceneNode->yaw(m_cameraRotateSpeed); 
		}
		world->calcMouseDirection(); 
		world->movePickedBodyTo(); 
	}
	void Evolution::camera_lookright() 		
	{ 
		BeSceneNode* const sceneNode=world->m_camera.getSceneNode();
		if(sceneNode)
		{
			sceneNode->yaw(-m_cameraRotateSpeed);
		}
		world->calcMouseDirection(); 
		world->movePickedBodyTo(); 
	}
	void Evolution::camera_rollleft() 		
	{ 
		BeSceneNode* const sceneNode=world->m_camera.getSceneNode();
		if(sceneNode)
		{
			sceneNode->roll(m_cameraRotateSpeed); 		
		}
		world->calcMouseDirection(); 
		world->movePickedBodyTo(); 
	}
	void Evolution::camera_rollright() 		
	{ 
		BeSceneNode* const sceneNode=world->m_camera.getSceneNode();
		if(sceneNode)
		{
			sceneNode->roll(-m_cameraRotateSpeed); 
		}	
		world->calcMouseDirection(); 
		world->movePickedBodyTo(); 
	}
	
	
// 	void Evolution::camera_movedown() { world->camera.moveDown(0.01f); world->movePickedBodyFrom(); }
// 	void Evolution::camera_moveforward() { world->camera.moveForward(0.01f); world->movePickedBodyFrom(); }
// 	void Evolution::camera_movebackward() { world->camera.moveBackward(0.01f); world->movePickedBodyFrom(); }
// 	void Evolution::camera_moveleft() { world->camera.moveLeft(0.01f); world->movePickedBodyFrom(); }
// 	void Evolution::camera_moveright() { world->camera.moveRight(0.01f); world->movePickedBodyFrom(); }
// 	void Evolution::camera_lookup() { world->camera.lookUp(0.001f); world->calcMouseDirection(); world->movePickedBodyTo(); }
// 	void Evolution::camera_lookdown() { world->camera.lookDown(0.001f); world->calcMouseDirection(); world->movePickedBodyTo(); }
// 	void Evolution::camera_lookleft() { world->camera.lookLeft(0.001f); world->calcMouseDirection(); world->movePickedBodyTo(); }
// 	void Evolution::camera_lookright() { world->camera.lookRight(0.001f); world->calcMouseDirection(); world->movePickedBodyTo(); }
// 	void Evolution::camera_rollleft() { world->camera.rollLeft(0.001f); world->calcMouseDirection(); world->movePickedBodyTo(); }
// 	void Evolution::camera_rollright() { world->camera.rollRight(0.001f); world->calcMouseDirection(); world->movePickedBodyTo(); }
// /*/*/*	void Evolution::camera_lookhorizontal() { world->camera.lookRight((float)world->relx/3000); world->calcMouseDirection(); world->movePickedBodyTo(); }
// 	void Evolution::camera_lookvertical() { world->camera.lookDown((float)world->rely/3000); world->calcMouseDirection(); world->movePickedBodyTo(); }
// 	void Evolution::camera_movehorizontal() { world->camera.moveRight((float)world->relx/300); world->movePickedBodyFrom(); }
// 	void Evolution::camera_movevertical() { world->camera.moveDown((float)world->rely/300); world->movePickedBodyFrom(); }*/*/*/

	void Evolution::unregisterCritterVID(int vectorID)
	{
		world->critterselection->unregisterCritterVID(vectorID);
	}

	void Evolution::clear()
	{
		world->critterselection->clear();
	}

	void Evolution::gui_selectCritter(int c)
	{
		canvas->children["critterview"]->active = true;
		canvas->raisePanel(canvas->children["critterview"]);
		world->critterselection->selectCritterVID(c);
	}

	void Evolution::gui_swap()
	{
		canvas->swap();
	}

	void Evolution::canvas_setx( float value )
	{
		canvas->moveMouseX(value);

		if ( !world->mouselook )
			world->mousex = value;
	}

	void Evolution::canvas_sety( float value )
	{
		canvas->moveMouseY(value);
		canvas->moveMouse();

		if ( !world->mouselook )
		{
			world->mousey = value;

			// world mouse dynamics
			world->calcMouseDirection();
			world->movePickedBodyTo();
		}		
	}
	
	void Evolution::canvas_press()
	{
		canvas->buttonPress( 1 );
		world->selectBody();
	}
	void Evolution::canvas_release()
	{
		canvas->buttonRelease( 1 );
	}
	void Evolution::canvas_pressAlt()
	{
		canvas->buttonPress( 3 );
		world->pickBody();
	}
	void Evolution::canvas_releaseAlt()
	{
		canvas->buttonRelease( 3 );
		world->unpickBody();
	}
	void Evolution::canvas_swapchild(const string& child)
	{
		canvas->swapChild( child );
	}


Evolution::~Evolution()
{
	delete world;
}
